#include "TCPServer.h"
#include "Util.hpp"
#include "foreach.h"

#include <iostream>

TCPServer::TCPServer(int Port)
        :mAcceptor(mIOService, tcp::endpoint(tcp::v4(), Port))
        ,ID(0)
{
    //ctor
}

TCPServer::~TCPServer()
{
    //dtor
}

bool TCPServer::Start()
{
    try
    {
        boost::thread trd(boost::bind( &TCPServer::MainThread, this ));
    }
    catch (std::logic_error const& le)
    {
        //std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        //std::cout << "TCPServer::Start::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        //std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }

    return true;
}

void TCPServer::MainThread()
{
    try
    {
        DoAccept();
        mIOService.run();
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "TCPServer::MainThread::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}

void TCPServer::DoAccept()
{
    try
    {
        Session * session = NULL;
        Session* s;
        foreach(s,mSessions)
        {
            if (!s->GetActive())
            {
                std::cout<<"used sesion\n";
                session = s;
                session->SetActive(true);
                session->Reset(new tcp::socket(mIOService));
                break;
            }
        }

        if (session==NULL)
        {
            std::cout<<"new sesion\n";
            mSessions.push_back(new Session(new tcp::socket(mIOService), ID));
            session = mSessions[mSessions.size()-1];
            ID++;
        }

        mAcceptor.async_accept(*session->GetTCPSocket(),
                               boost::bind(&TCPServer::OnAccept, this,
                                           boost::asio::placeholders::error, session));
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "TCPServer::DoAccept::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }

}

void TCPServer::OnAccept(const boost::system::error_code& error, Session* session)
{
    if (!error)
    {
        try
        {
            Receive(error, session);

            std::list<EventListener*>::iterator iter;
            for (iter=mListeners.begin();iter!=mListeners.end();iter++)
            {
                (*iter)->OnConnect(session);
            }
            DoAccept();
        }
        catch (std::logic_error const& le)
        {
            std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
        }
        catch (boost::exception &e)
        {
            std::cout << "TCPServer::OnAccept::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
        }
        catch (...)
        {
            std::cout<<"UNKNOWN_ERROR"<<std::endl;
        }
    }
    if (error == boost::asio::error::eof)
    {
        std::cout<<"EOF"<<std::endl;
    }

}

void TCPServer::Send(const boost::array<char*, 1>& SendBuffer,std::size_t bytes_transferred, tcp::socket& socket)
{
    try
    {

        boost::asio::async_write(socket,
                                 boost::asio::buffer(SendBuffer,bytes_transferred),
                                 boost::bind(&TCPServer::Error, this,
                                             boost::asio::placeholders::error));
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "TCPServer::Send::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}
void TCPServer::Receive(const boost::system::error_code& error, Session* session)
{
    try
    {
        if (!error)
        {
            session->GetTCPSocket()->async_read_some(boost::asio::buffer(session->GetBuffer()),
                    boost::bind(&TCPServer::CreateBuffer, this, boost::asio::placeholders::error,
                                boost::asio::placeholders::bytes_transferred, session));
        }
        else
        {
            std::cout<<error<<std::endl;
        }
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "Receiver::Receive::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}
void TCPServer::CreateBuffer( const boost::system::error_code& error,std::size_t bytes_transferred, Session* session)
{
    try
    {
        session->SetErrorCode(error);
        if (error!=boost::asio::error::eof)
        {
            session->SetBytesSize(bytes_transferred);

            std::list<EventListener*>::iterator iter = mListeners.begin();
            for (;iter!=mListeners.end();iter++)
            {
                (*iter)->OnReceive(session);
            }

            Receive(error,session);
        }
        else
        {
            std::list<EventListener*>::iterator iter = mListeners.begin();
            for (;iter!=mListeners.end();iter++)
            {
                (*iter)->OnDisconnet(session);
            }
        }
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "Receiver::CreateBuffer::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}
void TCPServer::Error(const boost::system::error_code& error)
{
    if (error)
    {
        throw std::logic_error("ERRO AQUI!!");
    }
}

/// Adiciona um observador
void TCPServer::AddListener(EventListener* listener)
{
    mListeners.push_back(listener);
}

/// Retorna a lista de sockets
tcp::socket* TCPServer::GetSocket(int ID)
{
    return mSessions[ID]->GetTCPSocket();
}
